1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.collect;
18
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkState;
21 import static com.google.common.collect.CollectPreconditions.checkRemove;
22
23 import com.google.common.annotations.GwtCompatible;
24 import com.google.common.base.Objects;
25
26 import java.io.Serializable;
27 import java.util.Collection;
28 import java.util.Iterator;
29 import java.util.Map;
30 import java.util.Set;
31
32 import javax.annotation.Nullable;
33
34
35
36
37
38
39
40
41
42
43
44 @GwtCompatible(emulated = true)
45 abstract class AbstractBiMap<K, V> extends ForwardingMap<K, V>
46 implements BiMap<K, V>, Serializable {
47
48 private transient Map<K, V> delegate;
49 transient AbstractBiMap<V, K> inverse;
50
51
52 AbstractBiMap(Map<K, V> forward, Map<V, K> backward) {
53 setDelegates(forward, backward);
54 }
55
56
57 private AbstractBiMap(Map<K, V> backward, AbstractBiMap<V, K> forward) {
58 delegate = backward;
59 inverse = forward;
60 }
61
62 @Override protected Map<K, V> delegate() {
63 return delegate;
64 }
65
66
67
68
69 K checkKey(@Nullable K key) {
70 return key;
71 }
72
73
74
75
76 V checkValue(@Nullable V value) {
77 return value;
78 }
79
80
81
82
83
84 void setDelegates(Map<K, V> forward, Map<V, K> backward) {
85 checkState(delegate == null);
86 checkState(inverse == null);
87 checkArgument(forward.isEmpty());
88 checkArgument(backward.isEmpty());
89 checkArgument(forward != backward);
90 delegate = forward;
91 inverse = new Inverse<V, K>(backward, this);
92 }
93
94 void setInverse(AbstractBiMap<V, K> inverse) {
95 this.inverse = inverse;
96 }
97
98
99
100 @Override public boolean containsValue(@Nullable Object value) {
101 return inverse.containsKey(value);
102 }
103
104
105
106 @Override public V put(@Nullable K key, @Nullable V value) {
107 return putInBothMaps(key, value, false);
108 }
109
110 @Override
111 public V forcePut(@Nullable K key, @Nullable V value) {
112 return putInBothMaps(key, value, true);
113 }
114
115 private V putInBothMaps(@Nullable K key, @Nullable V value, boolean force) {
116 checkKey(key);
117 checkValue(value);
118 boolean containedKey = containsKey(key);
119 if (containedKey && Objects.equal(value, get(key))) {
120 return value;
121 }
122 if (force) {
123 inverse().remove(value);
124 } else {
125 checkArgument(!containsValue(value), "value already present: %s", value);
126 }
127 V oldValue = delegate.put(key, value);
128 updateInverseMap(key, containedKey, oldValue, value);
129 return oldValue;
130 }
131
132 private void updateInverseMap(
133 K key, boolean containedKey, V oldValue, V newValue) {
134 if (containedKey) {
135 removeFromInverseMap(oldValue);
136 }
137 inverse.delegate.put(newValue, key);
138 }
139
140 @Override public V remove(@Nullable Object key) {
141 return containsKey(key) ? removeFromBothMaps(key) : null;
142 }
143
144 private V removeFromBothMaps(Object key) {
145 V oldValue = delegate.remove(key);
146 removeFromInverseMap(oldValue);
147 return oldValue;
148 }
149
150 private void removeFromInverseMap(V oldValue) {
151 inverse.delegate.remove(oldValue);
152 }
153
154
155
156 @Override public void putAll(Map<? extends K, ? extends V> map) {
157 for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
158 put(entry.getKey(), entry.getValue());
159 }
160 }
161
162 @Override public void clear() {
163 delegate.clear();
164 inverse.delegate.clear();
165 }
166
167
168
169 @Override
170 public BiMap<V, K> inverse() {
171 return inverse;
172 }
173
174 private transient Set<K> keySet;
175
176 @Override public Set<K> keySet() {
177 Set<K> result = keySet;
178 return (result == null) ? keySet = new KeySet() : result;
179 }
180
181 private class KeySet extends ForwardingSet<K> {
182 @Override protected Set<K> delegate() {
183 return delegate.keySet();
184 }
185
186 @Override public void clear() {
187 AbstractBiMap.this.clear();
188 }
189
190 @Override public boolean remove(Object key) {
191 if (!contains(key)) {
192 return false;
193 }
194 removeFromBothMaps(key);
195 return true;
196 }
197
198 @Override public boolean removeAll(Collection<?> keysToRemove) {
199 return standardRemoveAll(keysToRemove);
200 }
201
202 @Override public boolean retainAll(Collection<?> keysToRetain) {
203 return standardRetainAll(keysToRetain);
204 }
205
206 @Override public Iterator<K> iterator() {
207 return Maps.keyIterator(entrySet().iterator());
208 }
209 }
210
211 private transient Set<V> valueSet;
212
213 @Override public Set<V> values() {
214
215
216
217
218 Set<V> result = valueSet;
219 return (result == null) ? valueSet = new ValueSet() : result;
220 }
221
222 private class ValueSet extends ForwardingSet<V> {
223 final Set<V> valuesDelegate = inverse.keySet();
224
225 @Override protected Set<V> delegate() {
226 return valuesDelegate;
227 }
228
229 @Override public Iterator<V> iterator() {
230 return Maps.valueIterator(entrySet().iterator());
231 }
232
233 @Override public Object[] toArray() {
234 return standardToArray();
235 }
236
237 @Override public <T> T[] toArray(T[] array) {
238 return standardToArray(array);
239 }
240
241 @Override public String toString() {
242 return standardToString();
243 }
244 }
245
246 private transient Set<Entry<K, V>> entrySet;
247
248 @Override public Set<Entry<K, V>> entrySet() {
249 Set<Entry<K, V>> result = entrySet;
250 return (result == null) ? entrySet = new EntrySet() : result;
251 }
252
253 private class EntrySet extends ForwardingSet<Entry<K, V>> {
254 final Set<Entry<K, V>> esDelegate = delegate.entrySet();
255
256 @Override protected Set<Entry<K, V>> delegate() {
257 return esDelegate;
258 }
259
260 @Override public void clear() {
261 AbstractBiMap.this.clear();
262 }
263
264 @Override public boolean remove(Object object) {
265 if (!esDelegate.contains(object)) {
266 return false;
267 }
268
269
270 Entry<?, ?> entry = (Entry<?, ?>) object;
271 inverse.delegate.remove(entry.getValue());
272
273
274
275
276
277 esDelegate.remove(entry);
278 return true;
279 }
280
281 @Override public Iterator<Entry<K, V>> iterator() {
282 final Iterator<Entry<K, V>> iterator = esDelegate.iterator();
283 return new Iterator<Entry<K, V>>() {
284 Entry<K, V> entry;
285
286 @Override public boolean hasNext() {
287 return iterator.hasNext();
288 }
289
290 @Override public Entry<K, V> next() {
291 entry = iterator.next();
292 final Entry<K, V> finalEntry = entry;
293
294 return new ForwardingMapEntry<K, V>() {
295 @Override protected Entry<K, V> delegate() {
296 return finalEntry;
297 }
298
299 @Override public V setValue(V value) {
300
301 checkState(contains(this), "entry no longer in map");
302
303 if (Objects.equal(value, getValue())) {
304 return value;
305 }
306 checkArgument(!containsValue(value),
307 "value already present: %s", value);
308 V oldValue = finalEntry.setValue(value);
309 checkState(Objects.equal(value, get(getKey())),
310 "entry no longer in map");
311 updateInverseMap(getKey(), true, oldValue, value);
312 return oldValue;
313 }
314 };
315 }
316
317 @Override public void remove() {
318 checkRemove(entry != null);
319 V value = entry.getValue();
320 iterator.remove();
321 removeFromInverseMap(value);
322 }
323 };
324 }
325
326
327
328 @Override public Object[] toArray() {
329 return standardToArray();
330 }
331 @Override public <T> T[] toArray(T[] array) {
332 return standardToArray(array);
333 }
334 @Override public boolean contains(Object o) {
335 return Maps.containsEntryImpl(delegate(), o);
336 }
337 @Override public boolean containsAll(Collection<?> c) {
338 return standardContainsAll(c);
339 }
340 @Override public boolean removeAll(Collection<?> c) {
341 return standardRemoveAll(c);
342 }
343 @Override public boolean retainAll(Collection<?> c) {
344 return standardRetainAll(c);
345 }
346 }
347
348
349 private static class Inverse<K, V> extends AbstractBiMap<K, V> {
350 private Inverse(Map<K, V> backward, AbstractBiMap<V, K> forward) {
351 super(backward, forward);
352 }
353
354
355
356
357
358
359
360
361
362
363 @Override
364 K checkKey(K key) {
365 return inverse.checkValue(key);
366 }
367
368 @Override
369 V checkValue(V value) {
370 return inverse.checkKey(value);
371 }
372 }
373 }
374